
/*							*/
/*  Indexed Sequential Access Method			*/
/*  Relational Database Systems, Inc.			*/
/*							*/
/*		Proprietary Data			*/
/*    This document contains proprietary information	*/
/* and trade secrets which are the property of		*/
/* Relational Database Systems, Inc. (RDSI). This	*/
/* document is submitted to recipient in confidence.	*/
/* The information contained herein may not be used,	*/
/* copied or disclosed in whole or in part except as	*/
/* permitted by written agreement signed by an officer	*/
/* of RDSI.						*/
/*							*/

/*
 * buffer management routines
 *  operates on index file record buffers
 *
 * Relational Database Systems, Inc.
 * Roy Harrington	November 4, 1981
 *
 *   05-24-83	RVH	V104 -- added kernel installation code
 */

#include "isdec.c"

static int initflag = 0;			/* initialization flag	*/

/*
 * buffer initialization
 *  must be called once at start up
 */

STATIC int bfinit()
{
	register struct buff *bp;
	register char *cp;
	register int i;

	avbuffs.bf_forw = avbuffs.bf_back = &avbuffs; /* set up avail list */

#ifdef  ISALLOC
	buffs = (struct buff *) malloc(CASTUN nbuffs*sizeof(struct buff));
	buffers = malloc(CASTUN nbuffs*NODESIZE);
#endif  /* ISALLOC */

	bp = &buffs[0];
	cp = &buffers[0];

	for (i=0; i < nbuffs; i++, bp++)
	    {					/* set up each buffer	*/
	    bp->bf_flags = BFBUSY;
	    bp->bf_filep = NULL;
	    bp->bf_un.bf_addr = cp;
	    cp += NODESIZE;
	    bfrelease(bp);
	    }
	initflag = 1;
}

/*
 * buffer read
 * access an index node
 */

STATIC struct buff *bfread(daddr)
long daddr;
{
	register struct buff *bp;
	register char *addr;
	register int size;

	if (daddr <= 0L)
	    {
	    iserrno = EBADFILE;			/* bad file format	*/
	    return(NULL);
	    }

	bp = bfgetblk(daddr);
	if ( ! (bp->bf_flags & BFDONE))
	    {
	    if (lseek(filep->f_idxfd, bp->bf_daddr, 0) != bp->bf_daddr)
		{
		iserrio = IO_SEEK+IO_IDX;
		goto bad;
		}
	    addr = bp->bf_un.bf_addr;
	    size = (bp->bf_flags & BFDICT) ?
			sizeof(struct dict) : filep->f_idxsize+1;
	    if (read(filep->f_idxfd, addr, size) != size)
		{
		iserrio = IO_READ+IO_IDX;
		goto bad;
		}
	    bp->bf_used  = ld2(addr) & 0x7FFF;	/* load common data	*/
	    bp->bf_type  = ld1(addr+filep->f_idxsize-2);
	    bp->bf_level = ld1(addr+filep->f_idxsize-1) & 0x7F;
	    bp->bf_flags |= BFDONE;
	    }
	return(bp);

bad:	iserrno = errno;
	bfrelease(bp);
	return(NULL);
}

/*
 * get clear buffer
 */

STATIC struct buff *bfgetclr(daddr)
long daddr;
{
	register struct buff *bp;
	register int *intp, cnt;

	bp = bfgetblk(daddr);
	intp = bp->bf_un.bf_words;
	cnt = NODESIZE / sizeof(int);
	do
	    *intp++ = 0;
	while (--cnt);
	bp->bf_flags |= (BFMODF|BFDONE);
	return(bp);
}

/*
 * buffer get block
 *  allocate a buffer to hold block
 */

STATIC struct buff *bfgetblk(daddr)
long daddr;
{
	register struct buff *bp;
	register int i;
	long baddr;

	if (initflag == 0) bfinit();		/* initialize buffers	*/

	baddr = longmult((daddr-1), (long)(filep->f_idxsize+1));
	bp = &buffs[0];
	for (i=0; i < nbuffs; i++, bp++)
	    {
	    if (bp->bf_daddr == baddr && bp->bf_filep == filep)
		goto found;			/* match baddr & filep	*/
	    }

	bp = avbuffs.bf_back;			/* get available buffer	*/
	if (bp == &avbuffs)
	    error("no more buffers");
	if (bp->bf_flags & BFMODF)		/* write it if modified */
	    bfwrite(bp);
	bp->bf_daddr = baddr;			/* give it new identity	*/
	bp->bf_filep = filep;
	bp->bf_flags = (daddr == 1L) ? BFDICT : 0;

found:
	if (bp->bf_flags & BFBUSY)
	    error("buffer not free");
	bp->bf_flags |= BFBUSY;
	bp->bf_back->bf_forw = bp->bf_forw;	/* unlink from avail list */
	bp->bf_forw->bf_back = bp->bf_back;
	return(bp);
}


/*
 * release buffer to buffer pool
 */

STATIC int bfrelease(bp)
register struct buff *bp;
{
	register char *addr;

	if ( ! (bp->bf_flags & BFBUSY))
	    error("buffer not busy");
	bp->bf_flags &= ~BFBUSY;
	if (! (bp->bf_flags & BFDICT) && (bp->bf_flags & BFMODF))
	    {			/* if not dictionary and modified	*/
	    addr = bp->bf_un.bf_addr;
	    st2(bp->bf_used, addr);
	    st1(bp->bf_type, addr+bp->bf_filep->f_idxsize-2);
	    st1(bp->bf_level, addr+bp->bf_filep->f_idxsize-1);
	    }

	if (bp->bf_flags & BFMODF)
	    filep->f_flags |= FMODF;

	bp->bf_forw = avbuffs.bf_forw;		/* link to avail list	*/
	bp->bf_forw->bf_back = bp;
	avbuffs.bf_forw = bp;
	bp->bf_back = &avbuffs;
}

/*
 * delayed write of buffer
 *  just mark buffer for writing
 */

STATIC int bfdwrite(bp)
register struct buff *bp;
{
	bp->bf_flags |= BFMODF|BFDONE;
	bfrelease(bp);
}

/*
 * write out buffer
 */

STATIC int bfwrite(bp)
register struct buff *bp;
{
	register int fd, size;

	if (bp->bf_flags & BFBUSY)
	    bfrelease(bp);

	fd = bp->bf_filep->f_idxfd;
	size = (bp->bf_flags & BFDICT) ?
			sizeof(struct dict) : bp->bf_filep->f_idxsize+1;
	if (lseek(fd, bp->bf_daddr, 0) != bp->bf_daddr)
	    {
	    iserrno = errno;
	    iserrio = IO_SEEK+IO_IDX;
	    }
	else if (write(fd, bp->bf_un.bf_addr, size) != size)
	    {
	    iserrno = errno;
	    iserrio = IO_WRIT+IO_IDX;
	    }

	bp->bf_flags &= ~BFMODF;
	bp->bf_flags |= BFDONE;
}

/*
 * flush out any modified buffer
 */

STATIC int bfflush(fp)
struct ifile *fp;
{
	register struct buff *bp;
	register int i;

	bp = &buffs[0];
	for (i=0; i < nbuffs; i++, bp++)
	    {
	    if ( ! (bp->bf_flags & BFBUSY) && bp->bf_filep == fp &&
		    (bp->bf_flags & BFMODF))	/* write out any	*/
		bfwrite(bp);			/*  modified buffers	*/
	    }
}

/*
 * ignor buffers already containing data
 */

STATIC int bfignor(fp)
struct ifile *fp;
{
	register struct buff *bp;
	register int i;

	bp = &buffs[0];
	for (i=0; i < nbuffs; i++, bp++)
	    {
	    if ( ! (bp->bf_flags & BFBUSY) && bp->bf_filep == fp)
		{				/* match filep ?	*/
		if (bp->bf_flags & BFMODF)
		    error("ignoring modified buffer");
		bp->bf_filep = NULL;		/* yes, erase fileid	*/
		}
	    }
}

